home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Mac / Demo / waste / htmled.py next >
Text File  |  1996-05-07  |  21KB  |  827 lines

  1. # A minimal text editor.
  2. #
  3. # To be done:
  4. # - Functionality: find, etc.
  5.  
  6. from Menu import DrawMenuBar
  7. from FrameWork import *
  8. import Win
  9. import Qd
  10. import Res
  11. import Fm
  12. import waste
  13. import WASTEconst
  14. import Scrap
  15. import os
  16. import macfs
  17. import regsub
  18. import string
  19. import htmllib
  20.  
  21. WATCH = Qd.GetCursor(4).data
  22.  
  23. LEFTMARGIN=0
  24.  
  25. UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
  26.     None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style"]
  27.     
  28. # Style and size menu. Note that style order is important (tied to bit values)
  29. STYLES = [
  30.     ("Bold", "B"), ("Italic", "I"), ("Underline", "U"), ("Outline", "O"),
  31.     ("Shadow", ""), ("Condensed", ""), ("Extended", "")
  32.     ]
  33. SIZES = [ 9, 10, 12, 14, 18, 24]
  34.  
  35. # Sizes for HTML tag types
  36. HTML_SIZE={
  37.     'h1': 18,
  38.     'h2': 14
  39. }
  40.     
  41. BIGREGION=Qd.NewRgn()
  42. Qd.SetRectRgn(BIGREGION, -16000, -16000, 16000, 16000)
  43.  
  44. class WasteWindow(ScrolledWindow):
  45.     def open(self, path, name, data):
  46.         self.path = path
  47.         self.name = name
  48.         r = windowbounds(400, 400)
  49.         w = Win.NewWindow(r, name, 1, 0, -1, 1, 0x55555555)
  50.         self.wid = w
  51.         vr = LEFTMARGIN, 0, r[2]-r[0]-15, r[3]-r[1]-15
  52.         dr = (0, 0, vr[2], 0)
  53.         Qd.SetPort(w)
  54.         Qd.TextFont(4)
  55.         Qd.TextSize(9)
  56.         flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoOutlineHilite | \
  57.             WASTEconst.weDoMonoStyled | WASTEconst.weDoUndo
  58.         self.ted = waste.WENew(dr, vr, flags)
  59.         style, soup = self.getstylesoup(self.path)
  60.         self.ted.WEInsert(data, style, soup)
  61.         self.ted.WESetSelection(0,0)
  62.         self.ted.WECalText()
  63.         self.ted.WEResetModCount()
  64.         w.DrawGrowIcon()
  65.         self.scrollbars()
  66.         self.do_postopen()
  67.         self.do_activate(1, None)
  68.         
  69.     def getstylesoup(self, pathname):
  70.         if not pathname:
  71.             return None, None
  72.         oldrf = Res.CurResFile()
  73.         try:
  74.             rf = Res.OpenResFile(self.path)
  75.         except Res.Error:
  76.             return None, None
  77.         try:
  78.             hstyle = Res.Get1Resource('styl', 128)
  79.             hstyle.DetachResource()
  80.         except Res.Error:
  81.             hstyle = None
  82.         try:
  83.             hsoup = Res.Get1Resource('SOUP', 128)
  84.             hsoup.DetachResource()
  85.         except Res.Error:
  86.             hsoup = None
  87.         Res.CloseResFile(rf)
  88.         Res.UseResFile(oldrf)
  89.         return hstyle, hsoup
  90.                 
  91.     def do_idle(self, event):
  92.         (what, message, when, where, modifiers) = event
  93.         Qd.SetPort(self.wid)
  94.         self.ted.WEIdle()    
  95.         if self.ted.WEAdjustCursor(where, BIGREGION):
  96.             return
  97.         Qd.SetCursor(Qd.qd.arrow)
  98.         
  99.     def getscrollbarvalues(self):
  100.         dr = self.ted.WEGetDestRect()
  101.         vr = self.ted.WEGetViewRect()
  102.         vx = self.scalebarvalue(dr[0], dr[2], vr[0], vr[2])
  103.         vy = self.scalebarvalue(dr[1], dr[3], vr[1], vr[3])
  104.         return vx, vy
  105.         
  106.     def scrollbar_callback(self, which, what, value):
  107.         if which == 'y':
  108.             #
  109.             # "line" size is minimum of top and bottom line size
  110.             #
  111.             topline_off,dummy = self.ted.WEGetOffset((1,1))
  112.             topline_num = self.ted.WEOffsetToLine(topline_off)
  113.             toplineheight = self.ted.WEGetHeight(topline_num, topline_num+1)
  114.  
  115.             botlinepos = self.ted.WEGetViewRect()[3]            
  116.             botline_off, dummy = self.ted.WEGetOffset((1, botlinepos-1))
  117.             botline_num = self.ted.WEOffsetToLine(botline_off)
  118.             botlineheight = self.ted.WEGetHeight(botline_num, botline_num+1)
  119.             
  120.             if botlineheight == 0:
  121.                 botlineheight = self.ted.WEGetHeight(botline_num-1, botline_num)
  122.             if botlineheight < toplineheight:
  123.                 lineheight = botlineheight
  124.             else:
  125.                 lineheight = toplineheight
  126.             if lineheight <= 0:
  127.                 lineheight = 1
  128.             #
  129.             # Now do the command.
  130.             #
  131.             if what == 'set':
  132.                 height = self.ted.WEGetHeight(0, 0x3fffffff)
  133.                 cur = self.getscrollbarvalues()[1]
  134.                 delta = (cur-value)*height/32767
  135.             if what == '-':
  136.                 delta = lineheight
  137.             elif what == '--':
  138.                 delta = (self.ted.WEGetViewRect()[3]-lineheight)
  139.                 if delta <= 0:
  140.                     delta = lineheight
  141.             elif what == '+':
  142.                 delta = -lineheight
  143.             elif what == '++':
  144.                 delta = -(self.ted.WEGetViewRect()[3]-lineheight)
  145.                 if delta >= 0:
  146.                     delta = -lineheight
  147.             self.ted.WEScroll(0, delta)
  148.         else:
  149.             if what == 'set':
  150.                 return # XXXX
  151.             vr = self.ted.WEGetViewRect()
  152.             winwidth = vr[2]-vr[0]
  153.             if what == '-':
  154.                 delta = winwidth/10
  155.             elif what == '--':
  156.                 delta = winwidth/2
  157.             elif what == '+':
  158.                 delta = -winwidth/10
  159.             elif what == '++':
  160.                 delta = -winwidth/2
  161.             self.ted.WEScroll(delta, 0)
  162.         # Pin the scroll
  163.         l, t, r, b = self.ted.WEGetDestRect()
  164.         vl, vt, vr, vb = self.ted.WEGetViewRect()
  165.         if t > 0 or l > 0:
  166.             dx = dy = 0
  167.             if t > 0: dy = -t
  168.             if l > 0: dx = -l
  169.             self.ted.WEScroll(dx, dy)
  170.         elif b < vb:
  171.             self.ted.WEScroll(0, vb-b)
  172.  
  173.         
  174.     def do_activate(self, onoff, evt):
  175.         Qd.SetPort(self.wid)
  176.         ScrolledWindow.do_activate(self, onoff, evt)
  177.         if onoff:
  178.             self.ted.WEActivate()
  179.             self.parent.active = self
  180.             self.parent.updatemenubar()
  181.         else:
  182.             self.ted.WEDeactivate()
  183.  
  184.     def do_update(self, wid, event):
  185.         region = wid.GetWindowPort().visRgn
  186.         if Qd.EmptyRgn(region):
  187.             return
  188.         Qd.EraseRgn(region)
  189.         self.ted.WEUpdate(region)
  190.         self.updatescrollbars()
  191.         
  192.     def do_postresize(self, width, height, window):
  193.         l, t, r, b = self.ted.WEGetViewRect()
  194.         vr = (l, t, l+width-15, t+height-15)
  195.         self.ted.WESetViewRect(vr)
  196.         Win.InvalRect(vr)
  197.         ScrolledWindow.do_postresize(self, width, height, window)
  198.         
  199.     def do_contentclick(self, local, modifiers, evt):
  200.         (what, message, when, where, modifiers) = evt
  201.         self.ted.WEClick(local, modifiers, when)
  202.         self.updatescrollbars()
  203.         self.parent.updatemenubar()
  204.  
  205.     def do_char(self, ch, event):
  206.         self.ted.WESelView()
  207.         (what, message, when, where, modifiers) = event
  208.         self.ted.WEKey(ord(ch), modifiers)
  209.         self.updatescrollbars()
  210.         self.parent.updatemenubar()
  211.         
  212.     def close(self):
  213.         if self.ted.WEGetModCount():
  214.             save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1)
  215.             if save > 0:
  216.                 self.menu_save()
  217.             elif save < 0:
  218.                 return
  219.         if self.parent.active == self:
  220.             self.parent.active = None
  221.         self.parent.updatemenubar()
  222.         del self.ted
  223.         self.do_postclose()
  224.         
  225.     def menu_save(self):
  226.         if not self.path:
  227.             self.menu_save_as()
  228.             return # Will call us recursively
  229.         #
  230.         # First save data
  231.         #
  232.         dhandle = self.ted.WEGetText()
  233.         data = dhandle.data
  234.         fp = open(self.path, 'wb')  # NOTE: wb, because data has CR for end-of-line
  235.         fp.write(data)
  236.         if data[-1] <> '\r': fp.write('\r')
  237.         fp.close()
  238.         #
  239.         # Now save style and soup
  240.         #
  241.         oldresfile = Res.CurResFile()
  242.         try:
  243.             rf = Res.OpenResFile(self.path)
  244.         except Res.Error:
  245.             Res.CreateResFile(self.path)
  246.             rf = Res.OpenResFile(self.path)
  247.         styles = Res.Resource('')
  248.         soup = Res.Resource('')
  249.         self.ted.WECopyRange(0, 0x3fffffff, None, styles, soup)
  250.         styles.AddResource('styl', 128, '')
  251.         soup.AddResource('SOUP', 128, '')
  252.         Res.CloseResFile(rf)
  253.         Res.UseResFile(oldresfile)
  254.         
  255.         self.ted.WEResetModCount()
  256.         
  257.     def menu_save_as(self):
  258.         fss, ok = macfs.StandardPutFile('Save as:')
  259.         if not ok: return
  260.         self.path = fss.as_pathname()
  261.         self.name = os.path.split(self.path)[-1]
  262.         self.wid.SetWTitle(self.name)
  263.         self.menu_save()
  264.         
  265.     def menu_insert(self, fp):
  266.         self.ted.WESelView()
  267.         data = fp.read()
  268.         self.ted.WEInsert(data, None, None)
  269.         self.updatescrollbars()
  270.         self.parent.updatemenubar()
  271.         
  272.     def menu_insert_html(self, fp):
  273.         import htmllib
  274.         import formatter
  275.         f = formatter.AbstractFormatter(self)
  276.         
  277.         # Remember where we are, and don't update
  278.         Qd.SetCursor(WATCH)
  279.         start, dummy = self.ted.WEGetSelection()
  280.         self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 1)
  281.  
  282.         self.html_init()
  283.         p = MyHTMLParser(f)
  284.         p.feed(fp.read())
  285.         
  286.         # Restore updating, recalc, set focus
  287.         dummy, end = self.ted.WEGetSelection()
  288.         self.ted.WECalText()
  289.         self.ted.WESetSelection(start, end)
  290.         self.ted.WESelView()
  291.         self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 0)
  292.         Win.InvalRect(self.ted.WEGetViewRect())
  293.  
  294.         self.updatescrollbars()
  295.         self.parent.updatemenubar()
  296.         
  297.     def menu_cut(self):
  298.         self.ted.WESelView()
  299.         self.ted.WECut()
  300.         Scrap.ZeroScrap()
  301.         self.ted.WECut()
  302.         self.updatescrollbars()
  303.         self.parent.updatemenubar()
  304.         
  305.     def menu_copy(self):
  306.         Scrap.ZeroScrap()
  307.         self.ted.WECopy()
  308.         self.updatescrollbars()
  309.         self.parent.updatemenubar()
  310.         
  311.     def menu_paste(self):
  312.         self.ted.WESelView()
  313.         self.ted.WEPaste()
  314.         self.updatescrollbars()
  315.         self.parent.updatemenubar()
  316.         
  317.     def menu_clear(self):
  318.         self.ted.WESelView()
  319.         self.ted.WEDelete()
  320.         self.updatescrollbars()
  321.         self.parent.updatemenubar()
  322.  
  323.     def menu_undo(self):
  324.         self.ted.WEUndo()
  325.         self.updatescrollbars()
  326.         self.parent.updatemenubar()
  327.         
  328.     def menu_setfont(self, font):
  329.         font = Fm.GetFNum(font)
  330.         self.mysetstyle(WASTEconst.weDoFont, (font, 0, 0, (0,0,0)))
  331.         self.parent.updatemenubar()
  332.                 
  333.     def menu_modface(self, face):
  334.         self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoToggleFace, 
  335.             (0, face, 0, (0,0,0)))
  336.  
  337.     def menu_setface(self, face):
  338.         self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoReplaceFace, 
  339.             (0, face, 0, (0,0,0)))
  340.  
  341.     def menu_setsize(self, size):
  342.         self.mysetstyle(WASTEconst.weDoSize, (0, 0, size, (0,0,0)))
  343.                                 
  344.     def menu_incsize(self, size):
  345.         self.mysetstyle(WASTEconst.weDoAddSize, (0, 0, size, (0,0,0)))
  346.  
  347.     def mysetstyle(self, which, how):
  348.         self.ted.WESelView()
  349.         self.ted.WESetStyle(which, how)
  350.         self.parent.updatemenubar()
  351.                                 
  352.     def have_selection(self):
  353.         start, stop = self.ted.WEGetSelection()
  354.         return start < stop
  355.         
  356.     def can_paste(self):
  357.         return self.ted.WECanPaste()
  358.         
  359.     def can_undo(self):
  360.         which, redo = self.ted.WEGetUndoInfo()
  361.         which = UNDOLABELS[which]
  362.         if which == None: return None
  363.         if redo:
  364.             return "Redo "+which
  365.         else:
  366.             return "Undo "+which
  367.             
  368.     def getruninfo(self):
  369.         all = (WASTEconst.weDoFont | WASTEconst.weDoFace | WASTEconst.weDoSize)
  370.         dummy, mode, (font, face, size, color) = self.ted.WEContinuousStyle(all)
  371.         if not (mode & WASTEconst.weDoFont):
  372.             font = None
  373.         else:
  374.             font = Fm.GetFontName(font)
  375.         if not (mode & WASTEconst.weDoFace): fact = None
  376.         if not (mode & WASTEconst.weDoSize): size = None
  377.         return font, face, size
  378.         
  379.     #
  380.     # Methods for writer class for html formatter
  381.     #
  382.     
  383.     def html_init(self):
  384.         self.html_font = [12, 0, 0, 0]
  385.         self.html_style = 0
  386.         self.html_color = (0,0,0)
  387.         self.new_font(self.html_font)
  388.     
  389.     def new_font(self, font):
  390.         if font == None:
  391.             font = (12, 0, 0, 0)
  392.         font = map(lambda x:x, font)
  393.         for i in range(len(font)):
  394.             if font[i] == None:
  395.                 font[i] = self.html_font[i]
  396.         [size, italic, bold, tt] = font
  397.         self.html_font = font[:]
  398.         if tt:
  399.             font = Fm.GetFNum('Courier')
  400.         else:
  401.             font = Fm.GetFNum('Times')
  402.         if HTML_SIZE.has_key(size):
  403.             size = HTML_SIZE[size]
  404.         else:
  405.             size = 12
  406.         face = 0
  407.         if bold: face = face | 1
  408.         if italic: face = face | 2
  409.         face = face | self.html_style
  410.         self.ted.WESetStyle(WASTEconst.weDoFont | WASTEconst.weDoFace | 
  411.                 WASTEconst.weDoSize | WASTEconst.weDoColor,
  412.                 (font, face, size, self.html_color))
  413.         
  414.     def new_margin(self, margin, level):
  415.         self.ted.WEInsert('[Margin %s %s]'%(margin, level), None, None)
  416.         
  417.     def new_spacing(self, spacing):
  418.         self.ted.WEInsert('[spacing %s]'%spacing, None, None)
  419.             
  420.     def new_styles(self, styles):
  421.         self.html_style = 0
  422.         self.html_color = (0,0,0)
  423.         if 'anchor' in styles:
  424.             self.html_style = self.html_style | 4
  425.             self.html_color = (0xffff, 0, 0)
  426.         self.new_font(self.html_font)
  427.  
  428.     def send_paragraph(self, blankline):
  429.         self.ted.WEInsert('\r'*(blankline+1), None, None)
  430.         
  431.     def send_line_break(self):
  432.         self.ted.WEInsert('\r', None, None)
  433.         
  434.     def send_hor_rule(self, *args, **kw):
  435.         # Ignore ruler options, for now
  436.         dummydata = Res.Resource('')
  437.         self.ted.WEInsertObject('rulr', dummydata, (0,0))
  438.         
  439.     def send_label_data(self, data):
  440.         self.ted.WEInsert(data, None, None)
  441.         
  442.     def send_flowing_data(self, data):
  443.         self.ted.WEInsert(data, None, None)
  444.         
  445.     def send_literal_data(self, data):
  446.         data = regsub.gsub('\n', '\r', data)
  447.         data = string.expandtabs(data)
  448.         self.ted.WEInsert(data, None, None)
  449.         
  450. class Wed(Application):
  451.     def __init__(self):
  452.         Application.__init__(self)
  453.         self.num = 0
  454.         self.active = None
  455.         self.updatemenubar()
  456.         waste.STDObjectHandlers()
  457.         # Handler for horizontal ruler
  458.         waste.WEInstallObjectHandler('rulr', 'new ', self.newRuler)
  459.         waste.WEInstallObjectHandler('rulr', 'draw', self.drawRuler)
  460.         
  461.     def makeusermenus(self):
  462.         self.filemenu = m = Menu(self.menubar, "File")
  463.         self.newitem = MenuItem(m, "New window", "N", self.open)
  464.         self.openitem = MenuItem(m, "Open...", "O", self.openfile)
  465.         self.closeitem = MenuItem(m, "Close", "W", self.closewin)
  466.         m.addseparator()
  467.         self.saveitem = MenuItem(m, "Save", "S", self.save)
  468.         self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
  469.         m.addseparator()
  470.         self.insertitem = MenuItem(m, "Insert plaintext...", "", self.insertfile)
  471.         self.htmlitem = MenuItem(m, "Insert HTML...", "", self.inserthtml)
  472.         m.addseparator()
  473.         self.quititem = MenuItem(m, "Quit", "Q", self.quit)
  474.         
  475.         self.editmenu = m = Menu(self.menubar, "Edit")
  476.         self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
  477.         self.cutitem = MenuItem(m, "Cut", "X", self.cut)
  478.         self.copyitem = MenuItem(m, "Copy", "C", self.copy)
  479.         self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
  480.         self.clearitem = MenuItem(m, "Clear", "", self.clear)
  481.         
  482.         self.makefontmenu()
  483.         
  484.         # Groups of items enabled together:
  485.         self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem,
  486.             self.editmenu, self.fontmenu, self.facemenu, self.sizemenu,
  487.             self.insertitem]
  488.         self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
  489.         self.windowgroup_on = -1
  490.         self.focusgroup_on = -1
  491.         self.pastegroup_on = -1
  492.         self.undo_label = "never"
  493.         self.ffs_values = ()
  494.         
  495.     def makefontmenu(self):
  496.         self.fontmenu = Menu(self.menubar, "Font")
  497.         self.fontnames = getfontnames()
  498.         self.fontitems = []
  499.         for n in self.fontnames:
  500.             m = MenuItem(self.fontmenu, n, "", self.selfont)
  501.             self.fontitems.append(m)
  502.         self.facemenu = Menu(self.menubar, "Style")
  503.         self.faceitems = []
  504.         for n, shortcut in STYLES:
  505.             m = MenuItem(self.facemenu, n, shortcut, self.selface)
  506.             self.faceitems.append(m)
  507.         self.facemenu.addseparator()
  508.         self.faceitem_normal = MenuItem(self.facemenu, "Normal", "N", 
  509.             self.selfacenormal)
  510.         self.sizemenu = Menu(self.menubar, "Size")
  511.         self.sizeitems = []
  512.         for n in SIZES:
  513.             m = MenuItem(self.sizemenu, `n`, "", self.selsize)
  514.             self.sizeitems.append(m)
  515.         self.sizemenu.addseparator()
  516.         self.sizeitem_bigger = MenuItem(self.sizemenu, "Bigger", "+", 
  517.             self.selsizebigger)
  518.         self.sizeitem_smaller = MenuItem(self.sizemenu, "Smaller", "-", 
  519.             self.selsizesmaller)
  520.                     
  521.     def selfont(self, id, item, *rest):
  522.         if self.active:
  523.             font = self.fontnames[item-1]
  524.             self.active.menu_setfont(font)
  525.         else:
  526.             EasyDialogs.Message("No active window?")
  527.  
  528.     def selface(self, id, item, *rest):
  529.         if self.active:
  530.             face = (1<<(item-1))
  531.             self.active.menu_modface(face)
  532.         else:
  533.             EasyDialogs.Message("No active window?")
  534.  
  535.     def selfacenormal(self, *rest):
  536.         if self.active:
  537.             self.active.menu_setface(0)
  538.         else:
  539.             EasyDialogs.Message("No active window?")
  540.  
  541.     def selsize(self, id, item, *rest):
  542.         if self.active:
  543.             size = SIZES[item-1]
  544.             self.active.menu_setsize(size)
  545.         else:
  546.             EasyDialogs.Message("No active window?")
  547.  
  548.     def selsizebigger(self, *rest):
  549.         if self.active:
  550.             self.active.menu_incsize(2)
  551.         else:
  552.             EasyDialogs.Message("No active window?")
  553.  
  554.     def selsizesmaller(self, *rest):
  555.         if self.active:
  556.             self.active.menu_incsize(-2)
  557.         else:
  558.             EasyDialogs.Message("No active window?")
  559.  
  560.     def updatemenubar(self):
  561.         changed = 0
  562.         on = (self.active <> None)
  563.         if on <> self.windowgroup_on:
  564.             for m in self.windowgroup:
  565.                 m.enable(on)
  566.             self.windowgroup_on = on
  567.             changed = 1
  568.         if on:
  569.             # only if we have an edit menu
  570.             on = self.active.have_selection()
  571.             if on <> self.focusgroup_on:
  572.                 for m in self.focusgroup:
  573.                     m.enable(on)
  574.                 self.focusgroup_on = on
  575.                 changed = 1
  576.             on = self.active.can_paste()
  577.             if on <> self.pastegroup_on:
  578.                 self.pasteitem.enable(on)
  579.                 self.pastegroup_on = on
  580.                 changed = 1
  581.             on = self.active.can_undo()
  582.             if on <> self.undo_label:
  583.                 if on:
  584.                     self.undoitem.enable(1)
  585.                     self.undoitem.settext(on)
  586.                     self.undo_label = on
  587.                 else:
  588.                     self.undoitem.settext("Nothing to undo")
  589.                     self.undoitem.enable(0)
  590.                 changed = 1
  591.             if self.updatefontmenus():
  592.                 changed = 1
  593.         if changed:
  594.             DrawMenuBar()
  595.             
  596.     def updatefontmenus(self):
  597.         info = self.active.getruninfo()
  598.         if info == self.ffs_values:
  599.             return 0
  600.         # Remove old checkmarks
  601.         if self.ffs_values == ():
  602.             self.ffs_values = (None, None, None)
  603.         font, face, size = self.ffs_values
  604.         if font <> None:
  605.             fnum = self.fontnames.index(font)
  606.             self.fontitems[fnum].check(0)
  607.         if face <> None:
  608.             for i in range(len(self.faceitems)):
  609.                 if face & (1<<i):
  610.                     self.faceitems[i].check(0)
  611.         if size <> None:
  612.             for i in range(len(self.sizeitems)):
  613.                 if SIZES[i] == size:
  614.                     self.sizeitems[i].check(0)
  615.                 
  616.         self.ffs_values = info
  617.         # Set new checkmarks
  618.         font, face, size = self.ffs_values
  619.         if font <> None:
  620.             fnum = self.fontnames.index(font)
  621.             self.fontitems[fnum].check(1)
  622.         if face <> None:
  623.             for i in range(len(self.faceitems)):
  624.                 if face & (1<<i):
  625.                     self.faceitems[i].check(1)
  626.         if size <> None:
  627.             for i in range(len(self.sizeitems)):
  628.                 if SIZES[i] == size:
  629.                     self.sizeitems[i].check(1)
  630.         # Set outline/normal for sizes
  631.         if font:
  632.             exists = getfontsizes(font, SIZES)
  633.             for i in range(len(self.sizeitems)):
  634.                 if exists[i]:
  635.                     self.sizeitems[i].setstyle(0)
  636.                 else:
  637.                     self.sizeitems[i].setstyle(8)
  638.  
  639.     #
  640.     # Apple menu
  641.     #
  642.     
  643.     def do_about(self, id, item, window, event):
  644.         EasyDialogs.Message("A simple single-font text editor based on WASTE")
  645.             
  646.     #
  647.     # File menu
  648.     #
  649.  
  650.     def open(self, *args):
  651.         self._open(0)
  652.         
  653.     def openfile(self, *args):
  654.         self._open(1)
  655.  
  656.     def _open(self, askfile):
  657.         if askfile:
  658.             fss, ok = macfs.StandardGetFile('TEXT')
  659.             if not ok:
  660.                 return
  661.             path = fss.as_pathname()
  662.             name = os.path.split(path)[-1]
  663.             try:
  664.                 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
  665.                 data = fp.read()
  666.                 fp.close()
  667.             except IOError, arg:
  668.                 EasyDialogs.Message("IOERROR: "+`arg`)
  669.                 return
  670.         else:
  671.             path = None
  672.             name = "Untitled %d"%self.num
  673.             data = ''
  674.         w = WasteWindow(self)
  675.         w.open(path, name, data)
  676.         self.num = self.num + 1
  677.  
  678.     def insertfile(self, *args):
  679.         if self.active:
  680.             fss, ok = macfs.StandardGetFile('TEXT')
  681.             if not ok:
  682.                 return
  683.             path = fss.as_pathname()
  684.             try:
  685.                 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
  686.             except IOError, arg:
  687.                 EasyDialogs.Message("IOERROR: "+`arg`)
  688.                 return
  689.             self.active.menu_insert(fp)
  690.         else:
  691.             EasyDialogs.Message("No active window?")
  692.  
  693.     def inserthtml(self, *args):
  694.         if self.active:
  695.             fss, ok = macfs.StandardGetFile('TEXT')
  696.             if not ok:
  697.                 return
  698.             path = fss.as_pathname()
  699.             try:
  700.                 fp = open(path, 'r')
  701.             except IOError, arg:
  702.                 EasyDialogs.Message("IOERROR: "+`arg`)
  703.                 return
  704.             self.active.menu_insert_html(fp)
  705.         else:
  706.             EasyDialogs.Message("No active window?")
  707.  
  708.         
  709.     def closewin(self, *args):
  710.         if self.active:
  711.             self.active.close()
  712.         else:
  713.             EasyDialogs.Message("No active window?")
  714.         
  715.     def save(self, *args):
  716.         if self.active:
  717.             self.active.menu_save()
  718.         else:
  719.             EasyDialogs.Message("No active window?")
  720.         
  721.     def saveas(self, *args):
  722.         if self.active:
  723.             self.active.menu_save_as()
  724.         else:
  725.             EasyDialogs.Message("No active window?")
  726.             
  727.         
  728.     def quit(self, *args):
  729.         for w in self._windows.values():
  730.             w.close()
  731.         if self._windows:
  732.             return
  733.         raise self
  734.         
  735.     #
  736.     # Edit menu
  737.     #
  738.     
  739.     def undo(self, *args):
  740.         if self.active:
  741.             self.active.menu_undo()
  742.         else:
  743.             EasyDialogs.Message("No active window?")
  744.         
  745.     def cut(self, *args):
  746.         if self.active:
  747.             self.active.menu_cut()
  748.         else:
  749.             EasyDialogs.Message("No active window?")
  750.         
  751.     def copy(self, *args):
  752.         if self.active:
  753.             self.active.menu_copy()
  754.         else:
  755.             EasyDialogs.Message("No active window?")
  756.         
  757.     def paste(self, *args):
  758.         if self.active:
  759.             self.active.menu_paste()
  760.         else:
  761.             EasyDialogs.Message("No active window?")
  762.  
  763.     def clear(self, *args):
  764.         if self.active:
  765.             self.active.menu_clear()
  766.         else:
  767.             EasyDialogs.Message("No active window?")
  768.         
  769.     #
  770.     # Other stuff
  771.     #    
  772.  
  773.     def idle(self, event):
  774.         if self.active:
  775.             self.active.do_idle(event)
  776.             
  777.     def newRuler(self, obj):
  778.         """Insert a new ruler. Make it as wide as the window minus 2 pxls"""
  779.         ted = obj.WEGetObjectOwner()
  780.         l, t, r, b = ted.WEGetDestRect()
  781.         return r-l, 4
  782.         
  783.     def drawRuler(self, (l, t, r, b), obj):
  784.         y = (t+b)/2
  785.         Qd.MoveTo(l+2, y)
  786.         Qd.LineTo(r-2, y)
  787.         return 0
  788.             
  789. class MyHTMLParser(htmllib.HTMLParser):
  790.     
  791.     def anchor_bgn(self, href, name, type):
  792.         self.anchor = href
  793.         if self.anchor:
  794.             self.anchorlist.append(href)
  795.             self.formatter.push_style('anchor')
  796.  
  797.     def anchor_end(self):
  798.         if self.anchor:
  799.             self.anchor = None
  800.             self.formatter.pop_style()
  801.  
  802.             
  803. def getfontnames():
  804.     names = []
  805.     for i in range(256):
  806.         n = Fm.GetFontName(i)
  807.         if n: names.append(n)
  808.     return names
  809.     
  810. def getfontsizes(name, sizes):
  811.     exist = []
  812.     num = Fm.GetFNum(name)
  813.     for sz in sizes:
  814.         if Fm.RealFont(num, sz):
  815.             exist.append(1)
  816.         else:
  817.             exist.append(0)
  818.     return exist
  819.  
  820. def main():
  821.     App = Wed()
  822.     App.mainloop()
  823.     
  824. if __name__ == '__main__':
  825.     main()
  826.     
  827.